package com.hzw.saas.api.storage.enums;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ArrayUtil;

/**
 * 资源状态枚举
 *
 * @author zzl
 * @since 12/24/2020
 */
public enum ResourceStatusEnum {

    // 冻结
    FROZEN(StatusCode.ROOT_CODE, 100, "冻结"),
    // 正常
    NORMAL(StatusCode.ROOT_CODE, 200, "正常"),
    // 回收
    RECYCLED(StatusCode.ROOT_CODE, 300, "回收"),
    // 关联回收, 子文件等随父目录被回收
    RECYCLED_LINKED(RECYCLED.code, 301, "关联回收"),
    // 删除
    DELETED(StatusCode.ROOT_CODE, 400, "删除"),
    // 关联删除, 子文件等随父目录被删除
    DELETED_LINKED(DELETED.code, 401, "关联删除"),
    // 覆盖删除, 同名文件覆盖
    DELETED_COVER(DELETED.code, 402, "覆盖删除"),
    ;

    public static final String API_TEXT = "200-正常, 30X-回收, 40X-删除";

    private final Integer supCode;
    private final Integer code;
    private final String text;

    ResourceStatusEnum(Integer supCode, Integer code, String text) {
        this.supCode = supCode;
        this.code = code;
        this.text = text;
    }

    public Integer getCode() {
        return code;
    }

    public String getText() {
        return text;
    }

    /**
     * 自身与所有子状态
     *
     * @return
     */
    public List<Integer> groupCodes() {
        List<Integer> codes = this.subCodes();
        codes.add(this.getCode());
        return codes;
    }

    public List<Integer> subCodes() {
        List<Integer> result = new ArrayList<>();
        for (ResourceStatusEnum value : ResourceStatusEnum.values()) {
            if (Objects.equals(value.supCode, this.code)) {
                result.add(value.code);
            }
        }
        return result;
    }

    public static Integer rootCode() {
        return StatusCode.ROOT_CODE;
    }

    public static String getText(Integer code) {
        for (ResourceStatusEnum value : ResourceStatusEnum.values()) {
            if (Objects.equals(value.code, code))
                return value.text;
        }
        return "";
    }

    public static boolean isValid(Integer code) {
        ResourceStatusEnum instance = instance(code);
        return Objects.nonNull(instance);
    }

    public static void assertValid(Integer code) {
        ResourceStatusEnum instance = instance(code);
        Assert.notNull(instance, "资源状态未知：{}", code);
    }

    public static ResourceStatusEnum instance(Integer code) {
        for (ResourceStatusEnum value : ResourceStatusEnum.values()) {
            if (Objects.equals(value.code, code))
                return value;
        }
        return null;
    }

    public static List<Integer> listCodes(boolean withSubs, ResourceStatusEnum... statuses) {
        if (ArrayUtil.isEmpty(statuses)) {
            return new ArrayList<>();
        }
        List<Integer> codes = Arrays.stream(statuses).filter(Objects::nonNull).map(ResourceStatusEnum::getCode).collect(Collectors.toList());
        if (withSubs) {
            for (ResourceStatusEnum value : ResourceStatusEnum.values()) {
                if (codes.contains(value.supCode)) {
                    codes.add(value.code);
                }
            }
        }
        return codes;
    }

    public static List<Integer> excludeCodes(boolean excludeSubs, ResourceStatusEnum... statuses) {
        if (ArrayUtil.isEmpty(statuses)) {
            return Arrays.stream(ResourceStatusEnum.values()).map(ResourceStatusEnum::getCode).collect(Collectors.toList());
        }
        List<Integer> excludeCodes = Arrays.stream(statuses).filter(Objects::nonNull).map(ResourceStatusEnum::getCode).collect(Collectors.toList());
        List<Integer> result = new ArrayList<>();
        for (ResourceStatusEnum value : ResourceStatusEnum.values()) {
            if (excludeCodes.contains(value.code)) {
                continue;
            }
            if (excludeSubs && excludeCodes.contains(value.supCode)) {
                continue;
            }
            result.add(value.code);
        }
        return result;
    }

    private static class StatusCode {
        private static final Integer ROOT_CODE = 0;
    }
}
